// STL
#include <algorithm>    // std::sort()
#include <numeric>      // std::iota()
#include <vector>       // std::vector<>

// jScience
#include "jutility.hpp" // get_n_rand_unique_elements()

// this
#include "statsxx/optimization/EA/EAParam.hpp"    // EAParam
#include "statsxx/optimization/EA/Individual.hpp" // Individual


//
// DESC: Performs a k-point crossover between two individuals, mom and dad, producing two offspring, child1 and child2.
//
inline void crossover_kpoint(
                             const Individual &mom,
                             const Individual &dad,
                             // -----
                             Individual       &child1,
                             Individual       &child2,
                             // -----
                             const EAParam    &param
                             )
{
    // SELECTION OF k-POINTS FOR CROSSOVER ...

    // note: skip the last point in this selection, because we NEED it for below
    std::vector<int> pts(mom.genome.size()-1);
    std::iota( pts.begin(), pts.end(), 0 );

    std::vector<int> kpts = get_n_rand_unique_elements( param.xover_nk, pts );

    kpts.push_back(mom.genome.size()-1);

    std::sort( kpts.begin(), kpts.end() );


    // k-POINT CROSSOVER
    int startk = 0;
    int flip   = 0;
    for( auto &k : kpts )
    {
        if( (flip % 2) == 0 )
        {
            for( int i = startk; i <= k; ++i )
            {
                child1.genome.push_back(mom.genome[i]);
                child2.genome.push_back(dad.genome[i]);
            }
        }
        else
        {
            for( int i = startk; i <= k; ++i )
            {
                child1.genome.push_back(dad.genome[i]);
                child2.genome.push_back(mom.genome[i]);
            }
        }

        startk = (k+1);
        ++flip;
    }
}


